/* ---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *-------------------------------------------------------------------------------------------- */

import * as browser from "./browser";
import * as platform from "../common/platform";

export interface IMouseEvent {
  readonly browserEvent: MouseEvent;
  readonly leftButton: boolean;
  readonly middleButton: boolean;
  readonly rightButton: boolean;
  readonly target: HTMLElement;
  readonly detail: number;
  readonly posx: number;
  readonly posy: number;
  readonly ctrlKey: boolean;
  readonly shiftKey: boolean;
  readonly altKey: boolean;
  readonly metaKey: boolean;
  readonly timestamp: number;

  preventDefault(): void;
  stopPropagation(): void;
}

export class StandardMouseEvent implements IMouseEvent {
  public readonly browserEvent: MouseEvent;

  public readonly leftButton: boolean;
  public readonly middleButton: boolean;
  public readonly rightButton: boolean;
  public readonly target: HTMLElement;
  public detail: number;
  public readonly posx: number;
  public readonly posy: number;
  public readonly ctrlKey: boolean;
  public readonly shiftKey: boolean;
  public readonly altKey: boolean;
  public readonly metaKey: boolean;
  public readonly timestamp: number;

  constructor(e: MouseEvent) {
    this.timestamp = Date.now();
    this.browserEvent = e;
    this.leftButton = e.button === 0;
    this.middleButton = e.button === 1;
    this.rightButton = e.button === 2;

    this.target = <HTMLElement>e.target;

    this.detail = e.detail || 1;
    if (e.type === "dblclick") {
      this.detail = 2;
    }
    this.ctrlKey = e.ctrlKey;
    this.shiftKey = e.shiftKey;
    this.altKey = e.altKey;
    this.metaKey = e.metaKey;

    if (typeof e.pageX === "number") {
      this.posx = e.pageX;
      this.posy = e.pageY;
    } else {
      // Probably hit by MSGestureEvent
      this.posx = e.clientX + document.body.scrollLeft + document.documentElement?.scrollLeft;
      this.posy = e.clientY + document.body.scrollTop + document.documentElement?.scrollTop;
    }
  }

  public preventDefault(): void {
    if (this.browserEvent.preventDefault) {
      this.browserEvent.preventDefault();
    }
  }

  public stopPropagation(): void {
    if (this.browserEvent.stopPropagation) {
      this.browserEvent.stopPropagation();
    }
  }
}

export interface IDataTransfer {
  dropEffect: string;
  effectAllowed: string;
  types: any[];
  files: any[];

  setData(type: string, data: string): void;
  setDragImage(image: any, x: number, y: number): void;

  getData(type: string): string;
  clearData(types?: string[]): void;
}

export class DragMouseEvent extends StandardMouseEvent {
  public readonly dataTransfer: IDataTransfer;

  constructor(e: MouseEvent) {
    super(e);
    this.dataTransfer = (<any>e).dataTransfer;
  }
}

export interface IMouseWheelEvent extends MouseEvent {
  readonly wheelDelta: number;
}

interface IWebKitMouseWheelEvent {
  wheelDeltaY: number;
  wheelDeltaX: number;
}

interface IGeckoMouseWheelEvent {
  HORIZONTAL_AXIS: number;
  VERTICAL_AXIS: number;
  axis: number;
  detail: number;
}

export class StandardWheelEvent {
  public readonly browserEvent: IMouseWheelEvent | null;
  public readonly deltaY: number;
  public readonly deltaX: number;
  public readonly target: Node;

  constructor(e: IMouseWheelEvent | null, deltaX = 0, deltaY = 0) {
    this.browserEvent = e || null;
    this.target = e ? e.target || (<any>e).targetNode || e.srcElement : null;

    this.deltaY = deltaY;
    this.deltaX = deltaX;

    if (e) {
      const e1 = <IWebKitMouseWheelEvent>(<any>e);
      const e2 = <IGeckoMouseWheelEvent>(<any>e);

      // vertical delta scroll
      if (typeof e1.wheelDeltaY !== "undefined") {
        this.deltaY = e1.wheelDeltaY / 120;
      } else if (typeof e2.VERTICAL_AXIS !== "undefined" && e2.axis === e2.VERTICAL_AXIS) {
        this.deltaY = -e2.detail / 3;
      }

      // horizontal delta scroll
      if (typeof e1.wheelDeltaX !== "undefined") {
        if (browser.isSafari && platform.isWindows) {
          this.deltaX = -(e1.wheelDeltaX / 120);
        } else {
          this.deltaX = e1.wheelDeltaX / 120;
        }
      } else if (typeof e2.HORIZONTAL_AXIS !== "undefined" && e2.axis === e2.HORIZONTAL_AXIS) {
        this.deltaX = -e.detail / 3;
      }

      // Assume a vertical scroll if nothing else worked
      if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
        this.deltaY = e.wheelDelta / 120;
      }
    }
  }

  public preventDefault(): void {
    if (this.browserEvent) {
      if (this.browserEvent.preventDefault) {
        this.browserEvent.preventDefault();
      }
    }
  }

  public stopPropagation(): void {
    if (this.browserEvent) {
      if (this.browserEvent.stopPropagation) {
        this.browserEvent.stopPropagation();
      }
    }
  }
}
